﻿namespace Z2.Editor
{

	using System;
	using System.Drawing;
	using System.IO;
	using System.Windows.Forms;
	using System.Xml;

	/// <summary>
	/// Represents drawable unique object
	/// </summary>
	public class EditorObject
	{

		#region Members

		private Bitmap m_bitmap;
		private FieldType m_type;
		private string m_name;
		private string m_group;
		private int m_fw;
		private int m_fh;
		private bool m_front;
		private Rectangle m_rect;

		#endregion

		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name">Name of object (will be shown in menu)</param>
		/// <param name="node">Related <see cref="XmlNode"/> containing object data</param>
		public EditorObject(string name, XmlNode node)
		{
			this.m_name = name;
			// create & compose graphics path
			string file = string.Format("{0}.{1}", 
				node.Attributes[Constants.AttributeGraphics].Value, 
				node.Attributes[Constants.AttributeExt].Value);

			file = Path.Combine(Application.StartupPath, string.Format(@"Objects\{0}", file));

			// At first load all necessary attributes
			this.m_bitmap = (Bitmap) Bitmap.FromFile(file);
			this.m_bitmap.SetResolution(96, 96);
			this.m_type = EditorObject.GetFieldType(node.Name);
			if(node.Attributes[Constants.AttributeGroup] == null)
				throw new Exception(Constants.AttributeGroup + " attribute not defined on object " + name);
			this.m_group = node.Attributes[Constants.AttributeGroup].Value;

			// load optional attributes
			int framesX = 1;
			int framesY = 1;
			if (node.Attributes[Constants.AttributeFramesX] != null)
				framesX = Convert.ToInt32(node.Attributes[Constants.AttributeFramesX].Value);
			if (node.Attributes[Constants.AttributeFramesY] != null)
				framesY = Convert.ToInt32(node.Attributes[Constants.AttributeFramesY].Value);
			if (node.Attributes[Constants.AttributeFront] != null)
				this.m_front = Convert.ToBoolean(node.Attributes[Constants.AttributeFront].Value);

			// do necessary calculations
			this.m_fw = this.m_bitmap.Width / framesX;
			this.m_fh = this.m_bitmap.Height / framesY;
			this.m_rect = new Rectangle(0, 0, this.m_fw, this.m_fh);
		}

		#endregion

		#region Methods

		/// <summary>
		/// Static method that returns <see cref="FieldType"/> of this object, based on node name
		/// </summary>
		/// <param name="name">Node name</param>
		/// <returns><see cref="FieldType"/></returns>
		private static FieldType GetFieldType(string name)
		{
			if (string.Compare(name, Constants.ElementObject, true) == 0)
				return  FieldType.Object;
			if (string.Compare(name, Constants.ElementItem, true) == 0)
				return FieldType.Object;
			if (string.Compare(name, Constants.ElementField, true) == 0)
				return FieldType.Enviroment;

			throw new NotImplementedException(string.Format("Field type \"{0}\" is not implemented.", name));
		}

		/// <summary>
		/// Draws this object
		/// </summary>
		/// <param name="g"><see cref="Graphics"/></param>
		/// <param name="x">X position</param>
		/// <param name="y">Y position</param>
		public void Draw(Graphics g, int x, int y)
		{
			g.DrawImage(this.m_bitmap, x, y, this.m_rect, GraphicsUnit.Pixel);
		}

		/// <summary>
		/// Returns bitmap cutout for preview in the menu.
		/// </summary>
		/// <remarks>
		/// This method <strong>always</strong> returns new instance of <see cref="Bitmap"/>,
		/// so use it wisefully.
		/// </remarks>
		/// <returns><see cref="Bitmap."/></returns>
		public Bitmap GetBitmap()
		{
			Bitmap bmp = new Bitmap(m_fw, m_fh);
			Graphics g = Graphics.FromImage((Image)bmp);
			Rectangle rect = new Rectangle(0, 0, m_fw, m_fh);
			g.DrawImage(m_bitmap, 0, 0, rect, GraphicsUnit.Pixel);
			g.Dispose();
			return bmp;
		}

		#endregion

		#region Properties

		public bool IsFront
		{
			get { return this.m_front; }
		}

		public int FrameWidth
		{
			get { return m_fw; }
		}

		public int FrameHeight
		{
			get { return m_fh; }
		}
		public string Group
		{
			get { return this.m_group; }
		}

		public FieldType Type
		{
			get { return this.m_type; }
		}

		public string Name
		{
			get { return this.m_name; }
		}

		#endregion

	}
}
